﻿// Decompiled with JetBrains decompiler
// Type: Bannerlord.ModuleManager.ModuleUtilities
// Assembly: MCMv5, Version=5.10.2.0, Culture=neutral, PublicKeyToken=null
// MVID: 7AB326B9-B2B4-41C2-9177-68E944071101
// Assembly location: D:\steam\steamapps\workshop\content\261550\2859238197\bin\Win64_Shipping_Client\MCMv5.dll

using System;
using System.Collections.Generic;
using System.Linq;

#nullable enable
namespace Bannerlord.ModuleManager
{
  internal static class ModuleUtilities
  {
    public static bool AreDependenciesPresent(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended module)
    {
      foreach (DependentModuleMetadata dependentModuleMetadata in module.DependenciesLoadBeforeThisDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        if (!metadata.IsOptional && modules.All<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => !string.Equals(x.Id, metadata.Id, StringComparison.Ordinal))))
          return false;
      }
      foreach (DependentModuleMetadata dependentModuleMetadata in module.DependenciesIncompatiblesDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        if (modules.Any<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal))))
          return false;
      }
      return true;
    }

    public static IEnumerable<ModuleInfoExtended> GetDependencies(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended module)
    {
      HashSet<ModuleInfoExtended> visited = new HashSet<ModuleInfoExtended>();
      return ModuleUtilities.GetDependencies(modules, module, visited, new ModuleSorterOptions()
      {
        SkipOptionals = false,
        SkipExternalDependencies = false
      });
    }

    public static IEnumerable<ModuleInfoExtended> GetDependencies(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended module,
      ModuleSorterOptions options)
    {
      HashSet<ModuleInfoExtended> visited = new HashSet<ModuleInfoExtended>();
      return ModuleUtilities.GetDependencies(modules, module, visited, options);
    }

    public static IEnumerable<ModuleInfoExtended> GetDependencies(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended module,
      HashSet<ModuleInfoExtended> visited,
      ModuleSorterOptions options)
    {
      List<ModuleInfoExtended> dependencies = new List<ModuleInfoExtended>();
      ModuleSorter.Visit<ModuleInfoExtended>(module, (Func<ModuleInfoExtended, IEnumerable<ModuleInfoExtended>>) (x => ModuleUtilities.GetDependenciesInternal(modules, x, options)), (Action<ModuleInfoExtended>) (moduleToAdd =>
      {
        if (!(moduleToAdd != module))
          return;
        dependencies.Add(moduleToAdd);
      }), visited);
      return (IEnumerable<ModuleInfoExtended>) dependencies;
    }

    private static IEnumerable<ModuleInfoExtended> GetDependenciesInternal(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended module,
      ModuleSorterOptions options)
    {
      foreach (DependentModuleMetadata dependentModuleMetadata1 in module.DependenciesLoadBeforeThisDistinct())
      {
        DependentModuleMetadata dependentModuleMetadata = dependentModuleMetadata1;
        if (!dependentModuleMetadata.IsOptional || !options.SkipOptionals)
        {
          ModuleInfoExtended moduleInfo = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, dependentModuleMetadata.Id, StringComparison.Ordinal)));
          if ((dependentModuleMetadata.IsOptional || (object) moduleInfo != null) && moduleInfo != null)
            yield return moduleInfo;
          moduleInfo = (ModuleInfoExtended) null;
        }
      }
      if (!options.SkipExternalDependencies)
      {
        foreach (ModuleInfoExtended moduleInfo in (IEnumerable<ModuleInfoExtended>) modules)
        {
          foreach (DependentModuleMetadata dependentModuleMetadata2 in moduleInfo.DependenciesLoadAfterThisDistinct())
          {
            DependentModuleMetadata dependentModuleMetadata = dependentModuleMetadata2;
            if ((!dependentModuleMetadata.IsOptional || !options.SkipOptionals) && string.Equals(dependentModuleMetadata.Id, module.Id, StringComparison.Ordinal))
            {
              yield return moduleInfo;
              dependentModuleMetadata = (DependentModuleMetadata) null;
            }
          }
        }
      }
    }

    public static IEnumerable<ModuleIssue> ValidateModule(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      Func<ModuleInfoExtended, bool> isSelected)
    {
      HashSet<ModuleInfoExtended> visited = new HashSet<ModuleInfoExtended>();
      foreach (ModuleIssue issue in ModuleUtilities.ValidateModule(modules, targetModule, visited, isSelected, (Func<ModuleInfoExtended, bool>) (x => ModuleUtilities.ValidateModule(modules, x, isSelected).Count<ModuleIssue>() == 0)))
        yield return issue;
    }

    public static IEnumerable<ModuleIssue> ValidateModule(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      Func<ModuleInfoExtended, bool> isSelected,
      Func<ModuleInfoExtended, bool> isValid)
    {
      HashSet<ModuleInfoExtended> visited = new HashSet<ModuleInfoExtended>();
      foreach (ModuleIssue issue in ModuleUtilities.ValidateModule(modules, targetModule, visited, isSelected, isValid))
        yield return issue;
    }

    public static IEnumerable<ModuleIssue> ValidateModule(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      HashSet<ModuleInfoExtended> visitedModules,
      Func<ModuleInfoExtended, bool> isSelected,
      Func<ModuleInfoExtended, bool> isValid)
    {
      foreach (ModuleIssue issue in ModuleUtilities.ValidateModuleDependenciesDeclarations(modules, targetModule))
        yield return issue;
      foreach (ModuleIssue issue in ModuleUtilities.ValidateModuleDependencies(modules, targetModule, visitedModules, isSelected, isValid))
        yield return issue;
    }

    public static IEnumerable<ModuleIssue> ValidateModuleDependenciesDeclarations(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule)
    {
      foreach (string moduleId in targetModule.DependenciesToLoadDistinct().Select<DependentModuleMetadata, string>((Func<DependentModuleMetadata, string>) (x => x.Id)).Intersect<string>(targetModule.DependenciesIncompatiblesDistinct().Select<DependentModuleMetadata, string>((Func<DependentModuleMetadata, string>) (x => x.Id))))
        yield return new ModuleIssue(targetModule, moduleId, ModuleIssueType.DependencyConflictDependentAndIncompatible)
        {
          Reason = "Module '" + moduleId + "' is both depended upon and marked as incompatible"
        };
      foreach (DependentModuleMetadata dependency in targetModule.DependentModuleMetadatas.Where<DependentModuleMetadata>((Func<DependentModuleMetadata, bool>) (x => x.IsIncompatible && x.LoadType != 0)))
        yield return new ModuleIssue(targetModule, dependency.Id, ModuleIssueType.DependencyConflictDependentAndIncompatible)
        {
          Reason = "Module '" + dependency.Id + "' is both depended upon and marked as incompatible"
        };
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesLoadBeforeThisDistinct())
      {
        DependentModuleMetadata module = dependentModuleMetadata;
        DependentModuleMetadata metadata = targetModule.DependenciesLoadAfterThisDistinct().FirstOrDefault<DependentModuleMetadata>((Func<DependentModuleMetadata, bool>) (x => string.Equals(x.Id, module.Id, StringComparison.Ordinal)));
        if (metadata != null)
          yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.DependencyConflictDependentLoadBeforeAndAfter)
          {
            Reason = "Module '" + metadata.Id + "' is both depended upon as LoadBefore and LoadAfter"
          };
        metadata = (DependentModuleMetadata) null;
      }
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesToLoadDistinct().Where<DependentModuleMetadata>((Func<DependentModuleMetadata, bool>) (x => x.LoadType != 0)))
      {
        DependentModuleMetadata module = dependentModuleMetadata;
        ModuleInfoExtended moduleInfo = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, module.Id, StringComparison.Ordinal)));
        ModuleInfoExtended module1 = moduleInfo;
        DependentModuleMetadata metadata = (object) module1 != null ? module1.DependenciesToLoadDistinct().Where<DependentModuleMetadata>((Func<DependentModuleMetadata, bool>) (x => x.LoadType != 0)).FirstOrDefault<DependentModuleMetadata>((Func<DependentModuleMetadata, bool>) (x => string.Equals(x.Id, targetModule.Id, StringComparison.Ordinal))) : (DependentModuleMetadata) null;
        if (metadata != null && metadata.LoadType == module.LoadType)
          yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.DependencyConflictCircular)
          {
            Reason = "Circular dependencies. '" + targetModule.Id + "' and '" + moduleInfo.Id + "' depend on each other"
          };
        moduleInfo = (ModuleInfoExtended) null;
        metadata = (DependentModuleMetadata) null;
      }
    }

    public static IEnumerable<ModuleIssue> ValidateModuleDependencies(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      HashSet<ModuleInfoExtended> visitedModules,
      Func<ModuleInfoExtended, bool> isSelected,
      Func<ModuleInfoExtended, bool> isValid)
    {
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesToLoadDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        if (!metadata.IsOptional)
        {
          if (!modules.Any<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal))))
          {
            if (metadata.Version != ApplicationVersion.Empty)
              yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.MissingDependencies)
              {
                Reason = string.Format("Missing '{0}' {1}", (object) metadata.Id, (object) metadata.Version),
                SourceVersion = new ApplicationVersionRange(metadata.Version, metadata.Version)
              };
            else if (metadata.VersionRange != ApplicationVersionRange.Empty)
              yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.MissingDependencies)
              {
                Reason = string.Format("Missing '{0}' {1}", (object) metadata.Id, (object) metadata.VersionRange),
                SourceVersion = metadata.VersionRange
              };
            else
              yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.MissingDependencies)
              {
                Reason = "Missing '" + metadata.Id + "'"
              };
            yield break;
          }
        }
      }
      ModuleSorterOptions opts = new ModuleSorterOptions()
      {
        SkipOptionals = true,
        SkipExternalDependencies = true
      };
      ModuleInfoExtended[] moduleInfoExtendedArray = ModuleUtilities.GetDependencies((IReadOnlyCollection<ModuleInfoExtended>) modules, targetModule, visitedModules, opts).ToArray<ModuleInfoExtended>();
      for (int index = 0; index < moduleInfoExtendedArray.Length; ++index)
      {
        ModuleInfoExtended dependency = moduleInfoExtendedArray[index];
        DependentModuleMetadata metadata = targetModule.DependenciesAllDistinct().FirstOrDefault<DependentModuleMetadata>((Func<DependentModuleMetadata, bool>) (x => string.Equals(x.Id, dependency.Id, StringComparison.Ordinal)));
        if (metadata != null)
        {
          if ((object) metadata != null && metadata.LoadType == LoadType.LoadBeforeThis && !metadata.IsOptional && !metadata.IsIncompatible)
          {
            ModuleInfoExtended depencencyModuleInfo = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, dependency.Id, StringComparison.Ordinal)));
            if (depencencyModuleInfo == null)
            {
              yield return new ModuleIssue(targetModule, dependency.Id, ModuleIssueType.DependencyMissingDependencies)
              {
                Reason = "'" + dependency.Id + "' is missing it's dependencies!"
              };
              continue;
            }
            if (!isValid(depencencyModuleInfo))
              yield return new ModuleIssue(targetModule, dependency.Id, ModuleIssueType.DependencyValidationError)
              {
                Reason = "'" + dependency.Id + "' has unresolved issues!"
              };
            depencencyModuleInfo = (ModuleInfoExtended) null;
          }
          else
            continue;
        }
        metadata = (DependentModuleMetadata) null;
      }
      moduleInfoExtendedArray = (ModuleInfoExtended[]) null;
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesToLoadDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        if (!(metadata.Version == ApplicationVersion.Empty) || !(metadata.VersionRange == ApplicationVersionRange.Empty))
        {
          ModuleInfoExtended metadataModule = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal)));
          if (metadataModule != null)
          {
            if (metadata.Version != ApplicationVersion.Empty && !metadata.IsOptional && ApplicationVersionComparer.CompareStandard(metadata.Version, metadataModule.Version) > 0)
            {
              yield return new ModuleIssue(targetModule, metadataModule.Id, ModuleIssueType.VersionMismatchLessThanOrEqual)
              {
                Reason = string.Format("'{0}' wrong version <= {1}", (object) metadataModule.Id, (object) metadata.Version),
                SourceVersion = new ApplicationVersionRange(metadata.Version, metadata.Version)
              };
            }
            else
            {
              if (metadata.VersionRange != ApplicationVersionRange.Empty && !metadata.IsOptional)
              {
                if (ApplicationVersionComparer.CompareStandard(metadata.VersionRange.Min, metadataModule.Version) > 0)
                {
                  yield return new ModuleIssue(targetModule, metadataModule.Id, ModuleIssueType.VersionMismatchLessThan)
                  {
                    Reason = string.Format("'{0}' wrong version < [{1}]", (object) metadataModule?.Id, (object) metadata.VersionRange),
                    SourceVersion = metadata.VersionRange
                  };
                  continue;
                }
                if (ApplicationVersionComparer.CompareStandard(metadata.VersionRange.Max, metadataModule.Version) < 0)
                {
                  yield return new ModuleIssue(targetModule, metadataModule.Id, ModuleIssueType.VersionMismatchGreaterThan)
                  {
                    Reason = string.Format("'{0}' wrong version > [{1}]", (object) metadataModule.Id, (object) metadata.VersionRange),
                    SourceVersion = metadata.VersionRange
                  };
                  continue;
                }
              }
              metadataModule = (ModuleInfoExtended) null;
            }
          }
        }
      }
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesIncompatiblesDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        ModuleInfoExtended metadataModule = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal)));
        if ((object) metadataModule != null && isSelected(metadataModule))
        {
          if (isSelected(metadataModule))
            yield return new ModuleIssue(targetModule, metadataModule.Id, ModuleIssueType.Incompatible)
            {
              Reason = "'" + metadataModule.Id + "' is incompatible with this module"
            };
          metadataModule = (ModuleInfoExtended) null;
        }
      }
      foreach (ModuleInfoExtended module1 in (IEnumerable<ModuleInfoExtended>) modules)
      {
        ModuleInfoExtended module = module1;
        if (!string.Equals(module.Id, targetModule.Id, StringComparison.Ordinal) && isSelected(module))
        {
          foreach (DependentModuleMetadata dependentModuleMetadata in module.DependenciesIncompatiblesDistinct())
          {
            DependentModuleMetadata metadata = dependentModuleMetadata;
            if (string.Equals(metadata.Id, targetModule.Id, StringComparison.Ordinal))
            {
              if (isSelected(module))
                yield return new ModuleIssue(targetModule, module.Id, ModuleIssueType.Incompatible)
                {
                  Reason = "'" + module.Id + "' is incompatible with this module"
                };
              metadata = (DependentModuleMetadata) null;
            }
          }
          module = (ModuleInfoExtended) null;
        }
      }
    }

    public static IEnumerable<ModuleIssue> ValidateLoadOrder(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule)
    {
      HashSet<ModuleInfoExtended> visited = new HashSet<ModuleInfoExtended>();
      foreach (ModuleIssue issue in ModuleUtilities.ValidateLoadOrder(modules, targetModule, visited))
        yield return issue;
    }

    public static IEnumerable<ModuleIssue> ValidateLoadOrder(
      IReadOnlyList<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      HashSet<ModuleInfoExtended> visitedModules)
    {
      int targetModuleIdx = modules.IndexOf<ModuleInfoExtended>(targetModule);
      if (targetModuleIdx == -1)
      {
        yield return new ModuleIssue(targetModule, targetModule.Id, ModuleIssueType.Missing)
        {
          Reason = string.Format("Missing '{0}' {1} in modules list", (object) targetModule.Id, (object) targetModule.Version),
          SourceVersion = new ApplicationVersionRange(targetModule.Version, targetModule.Version)
        };
      }
      else
      {
        foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesToLoad().DistinctBy<DependentModuleMetadata, string>((Func<DependentModuleMetadata, string>) (x => x.Id)))
        {
          DependentModuleMetadata metadata = dependentModuleMetadata;
          int metadataIdx = modules.IndexOf<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => x.Id == metadata.Id));
          if (metadataIdx == -1)
          {
            if (!metadata.IsOptional)
            {
              if (metadata.Version != ApplicationVersion.Empty)
                yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.MissingDependencies)
                {
                  Reason = string.Format("Missing '{0}' {1}", (object) metadata.Id, (object) metadata.Version),
                  SourceVersion = new ApplicationVersionRange(metadata.Version, metadata.Version)
                };
              else if (metadata.VersionRange != ApplicationVersionRange.Empty)
                yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.MissingDependencies)
                {
                  Reason = string.Format("Missing '{0}' {1}", (object) metadata.Id, (object) metadata.VersionRange),
                  SourceVersion = metadata.VersionRange
                };
              else
                yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.MissingDependencies)
                {
                  Reason = "Missing '" + metadata.Id + "'"
                };
            }
          }
          else
          {
            if (metadata.LoadType == LoadType.LoadBeforeThis && metadataIdx > targetModuleIdx)
              yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.DependencyNotLoadedBeforeThis)
              {
                Reason = "'" + targetModule.Id + "' should be loaded before '" + metadata.Id + "'"
              };
            if (metadata.LoadType == LoadType.LoadAfterThis && metadataIdx < targetModuleIdx)
              yield return new ModuleIssue(targetModule, metadata.Id, ModuleIssueType.DependencyNotLoadedAfterThis)
              {
                Reason = "'" + targetModule.Id + "' should be loaded after '" + metadata.Id + "'"
              };
          }
        }
      }
    }

    public static void EnableModule(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      Func<ModuleInfoExtended, bool> getSelected,
      Action<ModuleInfoExtended, bool> setSelected,
      Func<ModuleInfoExtended, bool> getDisabled,
      Action<ModuleInfoExtended, bool> setDisabled)
    {
      HashSet<ModuleInfoExtended> visitedModules = new HashSet<ModuleInfoExtended>();
      ModuleUtilities.EnableModuleInternal(modules, targetModule, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
    }

    private static void EnableModuleInternal(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      HashSet<ModuleInfoExtended> visitedModules,
      Func<ModuleInfoExtended, bool> getSelected,
      Action<ModuleInfoExtended, bool> setSelected,
      Func<ModuleInfoExtended, bool> getDisabled,
      Action<ModuleInfoExtended, bool> setDisabled)
    {
      if (visitedModules.Contains(targetModule))
        return;
      visitedModules.Add(targetModule);
      setSelected(targetModule, true);
      ModuleSorterOptions options = new ModuleSorterOptions()
      {
        SkipOptionals = true,
        SkipExternalDependencies = true
      };
      ModuleInfoExtended[] array = ModuleUtilities.GetDependencies(modules, targetModule, options).ToArray<ModuleInfoExtended>();
      foreach (ModuleInfoExtended module1 in (IEnumerable<ModuleInfoExtended>) modules)
      {
        ModuleInfoExtended module = module1;
        if (!getSelected(module) && ((IEnumerable<ModuleInfoExtended>) array).Any<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (d => string.Equals(d.Id, module.Id, StringComparison.Ordinal))))
          ModuleUtilities.EnableModuleInternal(modules, module, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
      }
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesLoadAfterThisDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        if (!metadata.IsOptional && !metadata.IsIncompatible)
        {
          ModuleInfoExtended targetModule1 = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal)));
          if (targetModule1 != null && !getSelected(targetModule1))
            ModuleUtilities.EnableModuleInternal(modules, targetModule1, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
        }
      }
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesIncompatiblesDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        ModuleInfoExtended targetModule2 = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal)));
        if (targetModule2 != null)
        {
          if (getSelected(targetModule2))
            ModuleUtilities.DisableModuleInternal(modules, targetModule2, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
          setDisabled(targetModule2, true);
        }
      }
      foreach (ModuleInfoExtended module in (IEnumerable<ModuleInfoExtended>) modules)
      {
        foreach (DependentModuleMetadata dependentModuleMetadata in module.DependenciesIncompatiblesDistinct())
        {
          if (string.Equals(dependentModuleMetadata.Id, targetModule.Id, StringComparison.Ordinal))
          {
            if (getSelected(module))
              ModuleUtilities.DisableModuleInternal(modules, module, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
            setDisabled(module, getDisabled(module) | !ModuleUtilities.AreDependenciesPresent(modules, module));
          }
        }
      }
    }

    public static void DisableModule(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      Func<ModuleInfoExtended, bool> getSelected,
      Action<ModuleInfoExtended, bool> setSelected,
      Func<ModuleInfoExtended, bool> getDisabled,
      Action<ModuleInfoExtended, bool> setDisabled)
    {
      HashSet<ModuleInfoExtended> visitedModules = new HashSet<ModuleInfoExtended>();
      ModuleUtilities.DisableModuleInternal(modules, targetModule, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
    }

    private static void DisableModuleInternal(
      IReadOnlyCollection<ModuleInfoExtended> modules,
      ModuleInfoExtended targetModule,
      HashSet<ModuleInfoExtended> visitedModules,
      Func<ModuleInfoExtended, bool> getSelected,
      Action<ModuleInfoExtended, bool> setSelected,
      Func<ModuleInfoExtended, bool> getDisabled,
      Action<ModuleInfoExtended, bool> setDisabled)
    {
      if (visitedModules.Contains(targetModule))
        return;
      visitedModules.Add(targetModule);
      setSelected(targetModule, false);
      ModuleSorterOptions options = new ModuleSorterOptions()
      {
        SkipOptionals = true,
        SkipExternalDependencies = true
      };
      foreach (ModuleInfoExtended module in (IEnumerable<ModuleInfoExtended>) modules)
      {
        IEnumerable<ModuleInfoExtended> dependencies = ModuleUtilities.GetDependencies(modules, module, options);
        if (getSelected(module) && dependencies.Any<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (d => string.Equals(d.Id, targetModule.Id, StringComparison.Ordinal))))
          ModuleUtilities.DisableModuleInternal(modules, module, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
        foreach (DependentModuleMetadata dependentModuleMetadata in module.DependenciesLoadAfterThisDistinct())
        {
          if (string.Equals(dependentModuleMetadata.Id, targetModule.Id, StringComparison.Ordinal) && !dependentModuleMetadata.IsOptional && !dependentModuleMetadata.IsIncompatible && getSelected(module))
            ModuleUtilities.DisableModuleInternal(modules, module, visitedModules, getSelected, setSelected, getDisabled, setDisabled);
        }
        foreach (DependentModuleMetadata dependentModuleMetadata in module.DependenciesIncompatiblesDistinct())
        {
          if (string.Equals(dependentModuleMetadata.Id, targetModule.Id, StringComparison.Ordinal))
            setDisabled(module, getDisabled(module) & !ModuleUtilities.AreDependenciesPresent(modules, module));
        }
      }
      foreach (DependentModuleMetadata dependentModuleMetadata in targetModule.DependenciesIncompatiblesDistinct())
      {
        DependentModuleMetadata metadata = dependentModuleMetadata;
        ModuleInfoExtended moduleInfoExtended = modules.FirstOrDefault<ModuleInfoExtended>((Func<ModuleInfoExtended, bool>) (x => string.Equals(x.Id, metadata.Id, StringComparison.Ordinal)));
        if (moduleInfoExtended != null)
          setDisabled(moduleInfoExtended, false);
      }
    }
  }
}
